﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mogre;
using MogreNewt;

namespace WastedMechanics
{
    class MaterialManager
    {        
        public Dictionary<string, MaterialID> Materials;
        Dictionary<string, Dictionary<string, MaterialPair>> MaterialPairs;
        

        public void Initialise()
        {
            Materials = new Dictionary<string, MaterialID>();
            Materials["Level"] = new MaterialID(Engine.NewtonWorld);
            Materials["Character"] = new MaterialID(Engine.NewtonWorld);
            Materials["TriggerVolume"] = new MaterialID(Engine.NewtonWorld);
            Materials["Described"] = new MaterialID(Engine.NewtonWorld);
            Materials["GroundSensor"] = new MaterialID(Engine.NewtonWorld);            
            Materials["ClimbEdge"] = new MaterialID(Engine.NewtonWorld);
            Materials["Transparent"] = new MaterialID(Engine.NewtonWorld);

            MaterialPairs = new Dictionary<string, Dictionary<string, MaterialPair>>();
            foreach (string m1name in Materials.Keys)
                foreach (string m2name in Materials.Keys)
                {
                  //  if (m1name != m2name)
                    {
                        if (!MaterialPairs.Keys.Contains(m1name))
                            MaterialPairs[m1name] = new Dictionary<string, MaterialPair>();
                        //if (MaterialPairs[m2name][m1name] == null)
                        //{
                            MaterialPairs[m1name][m2name] = new MaterialPair(Engine.NewtonWorld, Materials[m1name], Materials[m2name]);
                            //MaterialPairs[m2name][m1name] = MaterialPairs[m1name][m2name];
//                        }
                    }
                }

            MaterialPairs["TriggerVolume"]["Character"].SetContactCallback(new TriggerVolumeGameObjectCallback());
            MaterialPairs["TriggerVolume"]["Described"].SetContactCallback(new IgnoreCollisionCallback());

            MaterialPairs["Character"]["ClimbEdge"].SetContactCallback(new IgnoreCollisionCallback());
            MaterialPairs["Character"]["Transparent"].SetContactCallback(new IgnoreCollisionCallback());
            MaterialPairs["Character"]["Level"].SetDefaultFriction(0.99f, 0.01f);            
            MaterialPairs["Character"]["Level"].SetDefaultElasticity(0.01f);
            MaterialPairs["Character"]["Described"].SetDefaultFriction(0.99f, 0.99f);            

            MaterialPairs["GroundSensor"]["Level"].SetContactCallback(new GroundSensorContactCallback());
            MaterialPairs["GroundSensor"]["Described"].SetContactCallback(new GroundSensorContactCallback());
            MaterialPairs["GroundSensor"]["Character"].SetContactCallback(new IgnoreCollisionCallback());
            MaterialPairs["GroundSensor"]["Transparent"].SetContactCallback(new IgnoreCollisionCallback());

            MaterialPairs["Described"]["Level"].SetDefaultFriction(0.9f, 0.99f);
            MaterialPairs["Described"]["Transparent"].SetContactCallback(new IgnoreCollisionCallback());

            MaterialPairs["Transparent"]["Transparent"].SetContactCallback(new IgnoreCollisionCallback());
            
        }

        public static bool CollisionsCollide(Body body0, Body body1, int threadIndex)
        {
            Vector3[] contactPoints;
            Vector3[] contactNormals;
            float[] contactPenetration;
            return (MogreNewt.CollisionTool.CollisionCollide(
                    Engine.NewtonWorld,
                    2,
                    body0.Collision,
                    body0.Orientation,
                    body0.Position,
                    body1.Collision,
                    body1.Orientation,
                    body1.Position,
                    out contactPoints,
                    out contactNormals,
                    out contactPenetration,
                    threadIndex) != 0);
        }

        class GroundSensorContactCallback : ContactCallback
        {
            public override int UserAABBOverlap(ContactMaterial material, Body body0, Body body1, int threadIndex)
            {
                if (CollisionsCollide(body0, body1, threadIndex))
                {
                    if (body0.UserData != body1.UserData)
                    {                        
                        if (body0.UserData is Character)
                            (body0.UserData as Character).SensedGround = 2;
                        else
                            (body1.UserData as Character).SensedGround = 2;
                    }
                }
                return 0;
            }
        }

        class IgnoreCollisionCallback : ContactCallback
        {
            public override int UserAABBOverlap(ContactMaterial material, Body body0, Body body1, int threadIndex)
            {
                return 0;
            }
        }

        class TriggerVolumeGameObjectCallback : ContactCallback
        {
            public override int UserAABBOverlap(ContactMaterial material, Body body0, Body body1, int threadIndex)
            {
                if (CollisionsCollide(body0, body1, threadIndex))
                {
                    if (body0.UserData is TriggerVolume)
                    {
                        TriggerVolume triggerVolume = body0.UserData as TriggerVolume;
                        triggerVolume.HandleGameObject((Character)body1.UserData);
                    }
                    else
                    {
                        TriggerVolume triggerVolume = body1.UserData as TriggerVolume;
                        triggerVolume.HandleGameObject((Character)body0.UserData);
                    }                    
                }
                return 0;
            }
        }            
    }
    
}
